<?php
namespace app\commands;

use app\models\Cron;
use app\models\Task;
use Yii;
use yii\console\Controller;

/**
 * 定时任务
 *
 * Class TaskController
 * @package app\commands
 */
class TaskController extends Controller
{
    /**
     * 每分钟执行一次
     */
    public function actionPerMinute()
    {
        $this->_do_task();
    }
    
    /**
     * 查找需要执行的定时任务f
     */
    private function _do_task()
    {
        // TODO：检测上次任务执行情况（上次没有执行完成，超时等）
        Yii::info('Begin Task');
        while (true) {
            /* @var $task \app\models\Task */
            $task = Task::find()
                ->andWhere(['status'=>Task::STATUS_WAITING])
                ->andWhere(['<=', 'next', time()])->one();
            if (empty($task)) {
                break;
            }
            Yii::info(print_r($task, true));
            $task->status = Task::STATUS_DOING;
            $task->save();
            $todo = json_decode($task->todo, true);
            $result = [];
            $result['begin_time'] = time();
            $result['result'] = (new \ReflectionClass($todo['class']))
                ->getMethod($todo['method'])
                ->invoke(null, $todo['params']);
            $result['end_time'] = time();
            $_del = false; // 是否允许执行完成后删除当前任务
            if (is_array($result['result'])
                && isset($result['result']['_del'])
                && $result['result']['_del'] === true) {
                $_del = true;
            }
            $status = Task::STATUS_FINISHED;
            $next = $task->next;
            if (!empty($task->cron)) {
                $_next = Cron::parse($task->cron, time() + 60);
                if (!empty($_next)) {
                    $status = Task::STATUS_WAITING;
                    $next = $_next;
                    $_del = false; // 循环的任务不能删除
                }
            }
            if ($_del) {
                $task->delete();
            } else {
                $task->status = $status;
                $task->next = $next;
                $task->result = json_encode($result);
                $task->save();
            }
        }
        // 清理老旧数据（状态完成或暂停的下次执行时间在一年前的任务）
        foreach (Task::find()
                     ->andWhere(['status'=>[Task::STATUS_FINISHED, Task::STATUS_PAUSED]])
                     ->andWhere(['<=', 'next', time() - 365 * 24 * 60 * 60])
                     ->each() as $task) {
            $task->delete();
            Yii::info('Clear Task:' . $task->id);
        }
        Yii::info('Finish Task');
    }
}
